package tw.right929.proxy
{
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	import flash.utils.Proxy;
	import flash.utils.flash_proxy;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	import tw.right929.event.AdvancedEventDispatcher;
	
	use namespace flash_proxy
	
	/**
	 * 每一個屬性都有bfs_XXX(before set XXX)和afs_XXX(after set XXX)的function，
	 * 代表在這個屬性被設定前和設定後，會呼叫的方法，這是可以累加的方法，
	 * 比如，若存在bfs_bfs_XXX會在呼叫bfs_XXX之前被呼叫。
	 * 
	 * 若該屬性是function則還會有bfc_XXX(before call XXX)和afc_XXX(after call XXX)的function，
	 * 代表這個方法在被呼叫前和呼叫後，會呼叫的方法，這也是可以累加的方法。
	 * 
	 * 上述的四個方法，是會混合的，
	 * 比如bfc_bfs_XXX這是會在bfs_XXX這個function被呼叫前呼叫的function。
	 * 
	 * 依然遵守繼承鏈的關係。
	 */
	public dynamic class AdvancedObject extends Proxy implements IEventDispatcher
	{
		/**
		 * 統一改變這個屬於這個類別物件的missFunction
		 */
		public static var missFunction:Function	=	function (name:*, rest:Array):* {return undefined};
		/**
		 * 統一改變這個屬於這個類別物件的missProperty
		 */
		public static var missProperty:Function	=	function (name:*):* {return undefined};
		
		private var _obj:Object			=	new Object();
		private var _properties:Array	=	new Array();
		private var _variables:Array	=	new Array();
		private var _functions:Array	=	new Array();
		private var _needUpdateProperties:Boolean	=	false;
		
		private var _superObj:Object;
		
		private var _missFunction:Function;
		private var _missProperty:Function;
		
		private var _eventDispatcher:AdvancedEventDispatcher;
		
		public function AdvancedObject()
		{
			super();
			_eventDispatcher	=	new AdvancedEventDispatcher(this);
		}
		
		/**
		 * 先看自已有沒有這個屬性，若沒有找superObj的，若superObj也沒有，幫自已新增這個屬性。
		 */
		override flash_proxy function setProperty(name:*, value:*):void
		{
			if(this[name] == value)
				return;
			
			_needUpdateProperties	=	true;
			
			var old:*	=	this[name];
			
			if(_hasProperty(name))
			{
				_beforeSet(name , value , old);
				_obj[name]	=	value;
				_afterSet(name , value , old);
			}
			else if(_superObj && _superObj.hasOwnProperty(name))
			{
				_beforeSet(name , value , old);
				_superObj[name] = value;
				_afterSet(name , value , old);
			}
			else
			{
				_beforeSet(name , value , old);
				_obj[name]	=	value;
				_afterSet(name , value , old);
			}
		}
		private function _beforeSet(name:* , newValue:* , oldValue:*):void
		{
			if(_hasProperty("bfs_"+name))
			{
				_callProperty("bfs_"+name , [oldValue , newValue]);
			}
		}
		private function _afterSet(name:* , newValue:* , oldValue:*):void
		{
			if(_hasProperty("afs_"+name))
			{
				_callProperty("afs_"+name , [oldValue , newValue]);
			}
		}
		
		/**
		 * 這個方法應該要只能刪掉自已的，不能刪掉繼承鏈上的屬性。
		 */
		override flash_proxy function deleteProperty(name:*):Boolean
		{
			_needUpdateProperties	=	true;
			return delete _obj[name]; 
		}
		
		/**
		 * 先看自已有沒有這個方法，若沒有呼叫superObj的，若superObj也沒有，統一呼叫這個物件的missFunction。
		 */
		override flash_proxy function callProperty(name:*, ... rest):*
		{
			return _callProperty(name , rest);
		}
		flash_proxy function _callProperty(name:* , rest:Array):*
		{
			var result:*;
			if(_hasProperty(name))
			{
				_beforeCall(name , rest);
				result	=	_obj[name].apply(this , rest);
				_afterCall(name , rest);
			}
			else if(_superObj && _superObj.hasOwnProperty(name))
			{
				_beforeCall(name , rest);
				if(_superObj is AdvancedObject)
				{
					result	=	_superObj._callProperty(name , rest);
				}
				else
				{
					result	=	_superObj[name].apply(this , rest);
				}
				_afterCall(name , rest);
			}
			else
			{
				result	=	missFunction(name , rest);
			}
			return result;
		}
		private function _beforeCall(name:* , parameters:Array):void
		{
			if(_hasProperty("bfc_"+name))
			{
				_callProperty("bfc_"+name , parameters);
			}
		}
		private function _afterCall(name:* , parameters:Array):void
		{
			if(_hasProperty("afc_"+name))
			{
				_callProperty("afc_"+name , parameters);
			}
		}
		
		/**
		 * 先看自已有沒有這個屬性，若沒有找superObj的，若superObj也沒有，統一呼叫這個物件的missProperty。
		 */
		override flash_proxy function getProperty(name:*):*
		{
			if(_hasProperty(name))
				return _obj[name];
			else if(_superObj && _superObj.hasOwnProperty(name))
				return _superObj[name];
			else
				return missProperty(name);
		}
		
		override flash_proxy function nextName(index:int):String
		{
			updateProperties();
			return _properties[index-1].toString();
		}
		
		override flash_proxy function nextNameIndex(index:int):int
		{
			updateProperties()
			if (index < _properties.length)
				return index + 1;
			else
				return 0;
		}
		
		override flash_proxy function nextValue(index:int):*
		{
			updateProperties();
			return _obj[_properties[index-1]];
		}
		
		override flash_proxy function isAttribute(name:*):Boolean
		{
			return true;
		}
		
		override flash_proxy function getDescendants(name:*):*
		{
			return _obj[name];
		}
		
		/**
		 * 尋找是否有這個屬性，包含superObj。
		 */
		override flash_proxy function hasProperty(name:*):Boolean
		{
			updateProperties();
			if(_hasProperty(name))
				return true;
			else if(_superObj && _superObj.hasOwnProperty(name))
				return true;
			else
				return false;
		}
		/**
		 * 尋找是否有這個屬性，不包含superObj。
		 */
		private function _hasProperty(name:*):Boolean
		{
			if(name is QName)
				name	=	name.localName;
			return(name in _obj);
		}
		
		/**
		 * 設定父物件。
		 */
		public final function set superObj(v:Object):void
		{
			_superObj	=	v;
			_eventDispatcher.eventSource	=	_superObj;
		}
		public final function get superObj():Object
		{
			return _superObj;
		}
		
		/**
		 * 若呼叫了不存在的方法，則會呼叫這個方法，預設值是傳回undefined。
		 */
		public final function set missFunction(v:Function):void
		{
			_missFunction	=	v;
		}
		public final function get missFunction():Function
		{
			if(_missFunction != null)
				return _missFunction;
			return getDefinitionByName(getQualifiedClassName(this))["missFunction"] as Function;
		}
		
		/**
		 * 若想取得不存在的屬性，則會呼叫這個方法，預設值是傳回undefined。
		 */
		public final function set missProperty(v:Function):void
		{
			_missProperty	=	v;
		}
		public final function get missProperty():Function
		{
			if(_missProperty != null)
				return _missProperty;
			return getDefinitionByName(getQualifiedClassName(this))["missProperty"] as Function;
		}
		
		/**
		 * 重整自已的屬性清單。
		 */
		private function updateProperties():void
		{
			if(checkNeedUpdate())
			{
				_properties	=	new Array();
				_variables	=	new Array();
				_functions	=	new Array();
				for (var p:String in _obj)
				{
					_properties.push(p);
					if(_obj[p] is Function)
						_functions.push(p);
					else
						_variables.push(p);
				}
				_needUpdateProperties	=	false;
			}
		}
		/**
		 * 確定自已的屬性是否有變化而需要更新。
		 */
		private function checkNeedUpdate():Boolean
		{
			if(_needUpdateProperties)
				return true;
			if(!_superObj)
				return false;
			if(!(_superObj is AdvancedObject))
				return true;
			return false;
		}
		
		
		public final function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
		{
			_eventDispatcher.addEventListener(type , listener , useCapture , priority , useWeakReference);
		}
		
		public final function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
		{
			_eventDispatcher.addEventListener(type , listener , useCapture);
		}
		
		public final function dispatchEvent(event:Event):Boolean
		{
			return _eventDispatcher.dispatchEvent(event);
		}
		
		public final function hasEventListener(type:String):Boolean
		{
			return _eventDispatcher.hasEventListener(type);
		}
		
		public final function willTrigger(type:String):Boolean
		{
			return _eventDispatcher.willTrigger(type);
		}
		
		public final function getAllEventListenerType():Array
		{
			return _eventDispatcher.getAllEventListenerType();
		}
		
		public final function removeAllEventListener():void
		{
			_eventDispatcher.removeAllEventListener();
		}
		
		public final function removeEventListenerByType(type:String):Array
		{
			return _eventDispatcher.removeEventListenerByType(type);
		}
		
		public final function addEventListenerByArray(listeners:Array):void
		{
			_eventDispatcher.addEventListenerByArray(listeners);
		}
	}
}
